# 8.1后的动手试一试
# 练习8.1
# def display_message():
#     print("The topic of this chapter is function.")
#
#
# display_message()
#
#
# def favorite_book(title):
#     print(f'One of my favorite books is {title}.')
#
#
# favorite_book("Alice in Wonderland")
#
#
# 8.3.2
# 空白可以是
# 空字符串''，空列表[]，空元组()，空字典{}，0，None
# def getFormattedName(firstName, lastName, middleName=''):
#     if middleName:
#         fullName = f'{firstName} {middleName} {lastName}'
#     else:
#         fullName = f'{firstName} {lastName}'
#     return fullName.title()
#
#
# musician = getFormattedName('jimi', 'hendrix')
# print(musician)
# musician = getFormattedName('john', 'hooker', 'lee')
# print(musician)
#
#
# # 8.3.3-1
# def buildPerson(firstName, lastName):
#     person = {
#         'first': firstName,
#         'last': lastName
#     }
#     return person
#
#
# musician = buildPerson('jimi', 'hendrix')
# print(musician)
#
#
# 8.3.3-2
# 这个函数在定义的时候，一开始不能直接给字典3个键值对
# 因为在实参传参的时候不一定有age这个参数，那么此时的字典中就不应该有和age相关的键值对
# 下面的  person['age'] = age  这句话实际上起了两个作用
#    1、为字典添加了一个关键字 'age'，
#    2、将形参中给到age的值 直接作为 'age' 这个关键字的值
#
# def buildPerson(firstName, lastName, age=None):
#     person = {
#         'first': firstName,
#         'last': lastName
#     }
#     if age:
#         person['age'] = age
#     return person
#
#
# musician = buildPerson('jimi', 'hendrix')
# print(musician)


# 8.3后面的动手试一试
# 练习8.6
"""
def city_country(city, country):
    ret = f"{city.title()}, {country.title()}"
    return ret


print(city_country('santiago', 'chile'))
print(city_country('beijing', 'china'))
"""

# 练习8.7
# 注意：实参想要修改默认参数时，不需要加单引号
"""
def make_album(make, album, NumOfAlb=None):
    musicInfo = {
        'make': make.title(),
        'album': album.title()
    }
    if NumOfAlb:
        musicInfo['NumOfAlb'] = NumOfAlb
    return musicInfo


print(make_album('zhou jielun', 'kua shi dai'))
print(make_album('xue zhiqian', 'shen shen ai guo ni'))
print(make_album('zhang jie', 'shi'))
print(make_album('lin junjie', 'xin di qiu', NumOfAlb=13))
"""

# 练习8.8
"""
def make_album(make, album, NumOfAlb=None):
    musicInfo = {
        'make': make.title(),
        'album': album.title()
    }
    if NumOfAlb:
        musicInfo['NumOfAlb'] = NumOfAlb
    return musicInfo


while True:
    print("\nPlease enter 'q' at any time to quit")
    make = input("Please write your favorite singer:")
    if make == 'q':
        break
    album = input("\nPlease write a favorite album written by he or she:")
    if album == 'q':
        break
    print(make_album(make, album))
"""
# 8.4.1
# 列表利用 pop()方法 和 append()方法 可以轻松实现一个列表的元素逆置
"""
def print_models(unprinted_designs, completed_models):
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        # print(f'Printing model: {current_design}')
        completed_models.append(current_design)
    return completed_models


def show_completed_models(completed_models):
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
        print(completed_model)


unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []
print(print_models(unprinted_designs, completed_models))
show_completed_models(completed_models)
"""

# 8.4.2
# 在 8.4.1 中提供的逆置代码会改变原来列表中的内容
# 依然可以使用上面的函数，但是需要创建  原来列表  的副本
# 创建副本可以利用列表的切片操作
"""
def print_models(unprinted_designs, completed_models):
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        # print(f'Printing model: {current_design}')
        completed_models.append(current_design)
    return completed_models


unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs[:], completed_models)
print(unprinted_designs)
print(completed_models)
"""

# 8.4后的动手试一试
# 练习8.10
# 下面的练习说明：python中的函数执行完毕后，
#              如果在函数中的形参是列表，在执行了函数之后修改了列表元素
#              则直接会影响函数外部作为实参的列表
#    这也说明了：python中的列表和C语言中的数组类似
#              把列表名作为参数传入时，函数中的操作是可以使得列表元素的值改变的
#
#              且普通的变量是不能改变的，比如：
"""
def testFun(a, b):
    a += 1
    b += 1
    print(a)
    print(b)


a = 1
b = 1
testFun(a, b)
print(a)
print(b)
"""

"""
def show_messages(listOfMessages):
    while listOfMessages:
        listOfMessage = listOfMessages.pop(0)
        print(listOfMessage)


def send_messages(listOfMessages, sent_messages):
    while listOfMessages:
        listOfMessage = listOfMessages.pop(0)
        sent_messages.append(listOfMessage)
    # return sent_messages


listOfMessages = ['Hello!', 'Good Bye!', 'Glad to see you!']
sent_messages = []
# show_messages(listOfMessages[:])
send_messages(listOfMessages[:], sent_messages)
print(sent_messages)
# print(send_messages(listOfMessages[:], sent_messages))
"""

# 8.5
# 传递任意数量的实参
# 下面的星号* 让toppings成为一个元组
# toppings作为一个元组类型的形参，可以接收任意数量的元素
"""
def make_pizza1(*toppings):
    print(toppings)


make_pizza1('pepperoni')
make_pizza1('mushroom', 'green peppers', 'extra cheese')
"""

# 8.5.1
#
# 重要！！！！！！！！！！！！！！！！！！！！！！！
#
# 如果要让函数接收不同类型的实参，
# 必须在函数定义中将接受任意数量实参的的形参放在最后！！
# python先匹配位置实参和关键字实参，再将其与的实参都收集到最后一个形参中
"""
def make_pizza2(size, *toppings):
    print(f'\nMaking a {size}-inch pizza with the following toppings:')
    for topping in toppings:
        print(f'- {topping}')


make_pizza2(12, 'pepperoni')
make_pizza1(16, 'mushrooms', 'green peppers', 'extra cheese')
"""

# 8.5.2
# 有时需要接受任意数量的实参，但预先不知道传递给函数的会是什么信息，
# 此时就可以在定义函数时直接定义一个字典，
# 当 传入函数的实参 的 位置参数和 能够与函数的形参直接匹配的关键字参数 都对应完毕后
# 此时如果仍有  形如  location='anshun' 这样的代码作为实参，
# 就需要可以接收键值对的形参，
# 即可以接受任意数量键值对的字典形参，这种形参的需要在其前面加两个星号*
"""
def build_profile(first, last, **user_info):
    user_info['first_name'] = first.title()
    user_info['last_name'] = last.title()
    return user_info
"""

# 写出下面的注意：
# 1、任意数量的实参总是放在最后，
# 2、这些参数全部都由 key= 'value' 的形式给出
# 3、在实参放在最后的形如2、中的键值对会先放入 类型为  **字典名的额形参中
#    即实参中如果有这样的参数满足：
#      1. 形如 key= 'value'
#      2. 其它所有的实参都是位置参数 或 与形参有相对应的key值的 关键字参数
# 4、最后创建的字典会把key视为字符串
"""
user_profile = build_profile('albert', 'einstein',
                             location='princeton',
                             field='physics')
print(user_profile)
"""

# 8.5后的动手试一试
# 练习8.12
"""
def foodMaterials(*args):
    print(f'Your ordered a {args[0]} sandwich with following toppings:')
    for arg in args:
        print(f'- {arg}')


foodMaterials('big', 'pepperoni', 'mushrooms', 'bacon')
"""

# 练习8.13
"""
def build_profile(first, last, **user_info):
    user_info['first_name'] = first.title()
    user_info['last_name'] = last.title()
    return user_info


def print_user_profile(user_profile):
    print(user_profile)
    for key, value in user_profile.items():
        print(f"{key}: {value}")


user_profile = build_profile('shi', 'maoqing',
                             location='Shanghai',
                             school='University of Shanghai for Science and Technology')
print_user_profile(user_profile)
"""

# 练习8.14
"""
def make_car(manufacture, version, **car_info):
    car_info['manufacture'] = manufacture
    car_info['version'] = version
    return car_info


print(make_car('subaru', 'outback', color='blue', tow_package=True))
"""

# 8.6.1
# 如果一个程序中有import这个语句时，
# 会将之后的模块中的所有代码都复制到这个程序中
"""
import test

unprinted_designs = ['bing dun dun', 'xue rong rong', 'xiong da', 'xiong er']
completed_models = []
test.print_models(unprinted_designs[:], completed_models)
print(unprinted_designs)
print(completed_models)
"""

# 8.6.2
# 导入特定的函数这句话形如下面这句，此时python的格式会提醒将这句话写道当前文件的最前面
"""
from test import build_profile, print_user_profile
user_profile = build_profile('si chuan', 'shu', first='zhao', last='zilong')
print_user_profile(user_profile)
"""

# 8.6.3
# 对于8.6.2中，利用as 可以给要导入的函数重新起一个别名，
# 方便在这个函数中引用，比如：
# from test import build_profile as b_p
# 这句话就是把要引入的函数起一个别名b_p，在下面引用的时候就可以直接使用b_p引用函数

# 8.6.4
# 对于8.6.1中，利用as 可以给要导入的模块重新起一个别名，比如：
# import test as t


# 8.6.5
# 8.6.1 和 8.6.2 的区别体现在调用函数时
# 8.6.1 是通过 点号. 进行函数的调用，将其视为方法
# 8.6.2 是通过 直接调用所导入的函数名，将其视为函数
# 如果既想一次性导入所有函数，又想通过导入的函数名直接调用，可以利用如下方法
from test import *
user_profile = build_profile('si chuan', 'shu', first='Zhao', last='Zilong')
print_user_profile(user_profile)
